package br.usp.icmc.biomac.shared;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;

public class Slider extends Composite  implements HasValueChangeHandlers<Integer> {
	    
	private int min; 
	private int max;
	private int step;
	private int value;
	

	private static SliderUiBinder uiBinder = GWT.create(SliderUiBinder.class);

	interface SliderUiBinder extends UiBinder<Widget, Slider> {
	}
	
	@UiField
	TextBox slide;
	@UiField
	TextBox count;
	
	
	/**
	 * constructor for Slider
	 * @author debra willrett
	 */
	public Slider() {
		initWidget(uiBinder.createAndBindUi(this));
		this.min = 1;
		this.max = 10;
		this.value = 1;
		this.step = 1;
		
		// set up the slider and counter as range and number types
		this.slide.getElement().setPropertyString("type", "range");
		this.count.getElement().setPropertyString("type", "number");
		
		// init the min, max and values for both
		this.slide.getElement().setPropertyString("min", Integer.toString(this.min));
		this.slide.getElement().setPropertyString("max", Integer.toString(this.max));
		this.slide.setValue(Integer.toString(this.value));
		this.slide.getElement().setPropertyString("step", Integer.toString(this.step));
		
		this.count.getElement().setPropertyString("min", Integer.toString(this.min));
		this.count.getElement().setPropertyString("max", Integer.toString(this.max));
		this.count.setValue(Integer.toString(this.value));
		this.count.getElement().setPropertyString("step", Integer.toString(this.step));
	}
	
	public void onLoad() {
		// init the min, max and values for both
		this.slide.getElement().setPropertyString("min", Integer.toString(this.min));
		this.slide.getElement().setPropertyString("max", Integer.toString(this.max));
		this.slide.setValue(Integer.toString(this.value));
		this.slide.getElement().setPropertyString("step", Integer.toString(this.step));
				
		this.count.getElement().setPropertyString("min", Integer.toString(this.min));
		this.count.getElement().setPropertyString("max", Integer.toString(this.max));
		this.count.setValue(Integer.toString(this.value));
		this.count.getElement().setPropertyString("step", Integer.toString(this.step));
		
	}

	
	/**
	 * onChangeSlide handles a change to the slider input type range 
	 * @param ChangeEvent e 
	 */
	@UiHandler("slide")
	void onChangeSlide(ChangeEvent e) {
		// get the new value
		Integer value = Integer.parseInt(slide.getValue());
		int old = this.value;
		this.value = value;
		this.count.setValue(Integer.toString(value));
		if (old != this.value)
			ValueChangeEvent.fire(this, value);

	}
	
	// verify the count text input and update count and slide to match
	private void updateCount() {

		// make sure user enters a number
		try {
			this.value = Integer.parseInt(count.getValue());
		}
		catch (NumberFormatException e) {
			this.value = -1;
		}	
	
		// and it is in the acceptable range
		this.max = this.slide.getElement().getPropertyInt("max");
		if (this.value < 1) {
			this.value = 1;
			this.count.setValue(Integer.toString(this.value));
		} else if (this.value > this.max) {
			// or bigger than max
			this.value = this.max;
			this.count.setValue(Integer.toString(this.value));
		} 
		
		// update slide to the new value
		this.slide.setValue(Integer.toString(this.value));

	}
	
	// handle a change to the count input
	@UiHandler("count")
	void onChangeCount(ChangeEvent e) {
		
		int old = this.value;
		updateCount();
		if (old != this.value) 
			ValueChangeEvent.fire(this, value);
	}	
	
	
	/**
	 * module update handles an update to the slider parameters, min, max value and step
	 * @param min
	 * @param max
	 * @param value
	 * @param step
	 */
	public void update(int min, int max, int value, int step) {
		setMin(min);
		setMax(max);
		setValue(value);
		setStep(step);	
	}
	
	/**
	 * module getValue gets the value of the slider
	 */
	public int getValue() {
		
		return this.value;
	}

	/**
	 * module setValue sets the value of the slider
	 * @param value - integer value of slider
	 */
	public void setValue(int value) {
		int old = this.value;
		this.value = value;
		slide.setValue(Integer.toString(value));
		count.setValue(Integer.toString(value));
		if (old != this.value)
			ValueChangeEvent.fire(this, this.value);
	}
	
	/**
	 * module getMin gets the min value of the slider
	 */
	public int getMin() {
		return this.min;
	}

	/**
	 * module setMin gets the value of the slider
	 * @param value - integer value of slider
	 */
	public void setMin(int min) {
		this.min = min;
		this.slide.getElement().setPropertyString("min", Integer.toString(this.min));
		this.count.getElement().setPropertyString("min", Integer.toString(this.min));
	}
	
	/**
	 * module getMax gets the max value of the slider
	 */
	public int getMax() {
		return this.max;
	}

	/**
	 * module setMax gets the max value of the slider
	 * @param max - maximum value of slider
	 */
	public void setMax(int max) {
		this.max = max;
		this.slide.getElement().setPropertyString("max", Integer.toString(this.max));
		this.count.getElement().setPropertyString("max", Integer.toString(this.max));
	}
	
	/**
	 * module getStep gets the step value of the slider
	 */
	public int getStep() {
		return this.step;
	}

	/**
	 * module setStep gets the step value of the slider
	 * @param step - integer value of slider
	 */
	public void setStep(int step) {
		this.step = step;
		this.slide.getElement().setPropertyString("step", Integer.toString(this.step));
		this.count.getElement().setPropertyString("step", Integer.toString(this.step));
	}


	@Override
	public HandlerRegistration addValueChangeHandler(
			final ValueChangeHandler<Integer> handler) {

			// This is really all we need to do to add a new Handler
			// addHandler is defined in Widget, and registers the Handler
			// with our HandlerManager

			return addHandler(handler, ValueChangeEvent.getType());
	}


}
